"""
对16位像素数据进行RLE压缩

最后更新: 2025年9月28日
"""


from operator import le


def compress_rle16(pixels):
    """
    对16位像素数据进行RLE压缩

    RLE压缩算法使用两种模式存储数据：
      - 游程编码(rle)：用于连续重复的像素值
      - 原始数据(abs)：用于不重复的像素值

    格式：
      - rle: [0x8000 | run_len, value]，run_len >= 2
      - abs: [abs_len, v1, v2, ...]，abs_len >= 1

    Args:
        pixels: 未压缩的原始16位像素值列表

    Returns:
        压缩后的数据列表
    """

    if not pixels:
        return []

    pixels_len = len(pixels)
    # 最大游程长度
    MAX_RUN_LEN = 0x7FFF
    # 最大literal长度
    MAX_LITERAL_LEN = 0x7FFF

    result = []
    i = 0
    while i < pixels_len:
        # 查找连续相同像素值的游程
        run_len = getRepeatCount(pixels[i:], MAX_RUN_LEN)

        if run_len > 2:
            # 3个以上相同值，使用游程编码
            result.append(0x8000 | run_len)
            result.append(pixels[i])
            i += run_len

        elif run_len < 2:
            # 收集原始数据块
            literal_len = getDifferenceCount(pixels[i:], MAX_LITERAL_LEN)
            result.append(literal_len)
            result.extend(pixels[i:(i + literal_len)])
            i += literal_len

        else:  # run_len == 2
            next_run_len = getRepeatCount(pixels[i+2:], 3)

            if next_run_len == 0 or next_run_len > 2:
                # 使用游程编码
                result.append(0x8000 | run_len)
                result.append(pixels[i])
                i += run_len
            else:
                # 收集原始数据块
                literal_len = getDifferenceCount(pixels[i+2:], MAX_LITERAL_LEN - 2)
                result.append(literal_len+2)
                result.extend(pixels[i:(i + literal_len+2)])
                i += literal_len + 2

    return result


def getRepeatCount(pixels, nMax) -> int:
    """获取重复像素值的游程长度

    Args:
        pixels -- 原始数据列表
        nMax -- 最大扫描长度
    Return:
        游程长度
    """
    pixels_len = len(pixels)
    if pixels_len == 0:
        return 0
    n = min(pixels_len, nMax)

    repeat_val = pixels[0]
    rle_len = 1
    while (rle_len < n):
        if repeat_val != pixels[rle_len]:
            break
        rle_len += 1
    return rle_len


def getDifferenceCount(pixels, nMax) -> int:
    """获取不连续像素值的长度

    Args:
        pixels -- 原始数据列表
        nMax -- 扫描长度
    Return:
      不连续长度
    """
    pixels_len = len(pixels)
    if pixels_len == 0:
        return 0
    n = min(pixels_len, nMax)

    literal_len = 1
    while (literal_len < n):
        next_run_len = getRepeatCount(pixels[literal_len:], 3)
        if next_run_len > 2:
            break
        literal_len += 1
    return literal_len
